package com.itany.shop.util;

import com.itany.shop.exception.DataAccessException;

import java.sql.*;
import java.util.ArrayList;
import java.util.List;

/**
 * @Author:石小俊
 * @Date:2022/12/15 10:16
 * @Version:1.0-SNAPSHOT
 * @Description: JDBC操作模板,封装了JDBC访问数据库的操作
 */
public class JDBCTemplate<T> {

    /**
     * 执行一个DML操作,即:insert、delete、update
     * @param sql   执行的sql语句
     * @param params    sql语句中需要的参数
     */
    public void update(String sql, Object... params){
        Connection conn = null;
        PreparedStatement ps = null;
        try {
            conn = JDBCUtil.getConnection();
            ps = conn.prepareStatement(sql);
            for(int i = 0; i < params.length; i++){
                ps.setObject(i+1,params[i]);
            }
            // 执行sql
            ps.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
            throw new DataAccessException("数据访问异常");
        } finally {
            JDBCUtil.close(null,ps,null);
        }
    }

    /**
     * 执行查询操作
     * @param sql   sql语句
     * @param rm    回调接口,将结果集转换成Java对象
     * @param params    sql的参数
     * @return  根据回调接口进行行映射之后,将所有的映射结果加入到集合中返回
     */
    public List<T> query(String sql, RowMapper rm, Object... params){
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        List<T> list = new ArrayList<>();
        try {
            conn = JDBCUtil.getConnection();
            ps = conn.prepareStatement(sql);
            for(int i = 0; i < params.length; i++){
                ps.setObject(i+1,params[i]);
            }
            rs = ps.executeQuery();
            while(rs.next()){
                // 执行行映射
                T t = (T) rm.mapRow(rs);
                // 将映射的结果加入到集合中
                list.add(t);
            }
            return list;
        } catch (SQLException e) {
            e.printStackTrace();
            throw new DataAccessException("数据访问异常");
        } catch (Exception e) {
            e.printStackTrace();
            throw new DataAccessException("数据访问异常");
        } finally {
            JDBCUtil.close(null,ps,rs);
        }
    }

    /**
     * 执行一个DML操作,用于保存记录时,返回生成的所有主键的值
     * @param psc   回调接口,创建符合需求的状态集
     * @param keyHolder 存储所有生成的键的值
     */
    public void update(PreparedStatementCreator psc, KeyHolder keyHolder){
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        List<Integer> list = new ArrayList();
        try {
            conn = JDBCUtil.getConnection();
            // 调用回调接口,获取到对应的状态集
            ps = psc.createPreparedStatement(conn);
            // 执行sql
            ps.executeUpdate();

            // 执行完sql之后,会生成对应的主键
            // 获取对应的结果集
            rs = ps.getGeneratedKeys();

            // 获取结果集元数据
            ResultSetMetaData rsmd = rs.getMetaData();
            // 获取当前返回的键的总列数
            int columnCount = rsmd.getColumnCount();

            if(rs.next()){
                // 遍历结果集中所有的列
                for(int i = 0; i < columnCount; i++){
                    // 将每一列的数据全部添加到集合中
                    list.add(rs.getInt(i+1));
                }
            }

            // 将集合交给keyHolder
            // 此时即将所有生成的键都交给了keyHolder
            keyHolder.setKeyList(list);
        } catch (Exception e) {
            e.printStackTrace();
            throw new DataAccessException("数据访问失败");
        } finally {
            JDBCUtil.close(null,ps,rs);
        }
    }
}
